home *** CD-ROM | disk | FTP | other *** search
/ CD Ware Multimedia 1995 May / cd Ware (Juegos) Epimundo.iso / DOS / PRGMMING / PCXKIT51.ZIP / PCX.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1994-12-04  |  19.7 KB  |  682 lines

  1. unit PCX;
  2.  
  3. (* {DEFINE RegisteredVersion} *)
  4. {$X+}
  5.  
  6. (* Requires Turbo/Borland Pascal for DOS, version 6 or later.
  7.  
  8.                                 Version 5.1
  9.                              Copyright (c) 1994
  10.                              by Peter Donnelly
  11.                               Skookum Software
  12.                               1301 Ryan Street
  13.                          Victoria BC Canada V8T 4Y8
  14.  
  15.    ╒══════════════════════════════════════════════════════════════════════╕
  16.    │  Permission is granted for the non-commercial distribution and       │
  17.    │  private use of this source code. This is shareware; if you use all  │
  18.    │  or portions of it in programs you distribute, or make any other     │
  19.    │  public use of it, you are expected to pay a modest registration     │
  20.    │  fee. Registered users will receive the latest version of the code,  │
  21.    │  including support for 256-color Super-VGA modes. Please see the     │
  22.    │  READ.ME file for details.                                           │
  23.    ╘══════════════════════════════════════════════════════════════════════╛
  24. *)
  25. INTERFACE
  26.  
  27. uses DOS, CRT;
  28.  
  29. CONST
  30.         NoOptions = $0000;        { to set bits for Options }
  31.         SaveMem =   $0001;
  32.         HCenter =   $0002;
  33.           VCenter =   $0004;
  34.         BlackOut =  $0008;
  35.         AutoSet = 0;              { can be passed to ReadIt }
  36.         NumModes = 11;
  37.         OurModes: array[1..NumModes] of word =
  38.                   ($0D, $0E, $10, $12, $13, $100,
  39.                    $101, $102, $103, $105, $107);
  40.         ErrNoOpen = 1;
  41.         ErrNoPal  = 2;
  42.         ErrTooWide= 3;
  43.         ErrColors = 4;
  44.         ErrNoSupp = 5;
  45.  
  46.  
  47. TYPE
  48.         RGBrec = record
  49.                    RedVal, GreenVal, BlueVal: byte;
  50.                  end;
  51.  
  52.         RGB256Rec = array[0..255] of RGBRec;
  53.  
  54.         PCXHeaderRec = record
  55.                          Signature: byte;
  56.                          Version: byte;
  57.                          Code: byte;
  58.                          BitsPerPlane: byte;
  59.                          XMin, YMin, XMax, YMax: word;
  60.                          HRes, VRes: word;
  61.                          Palette: array[0..15] of RGBRec;
  62.                          Reserved: byte;
  63.                          NumPlanes: byte;
  64.                          BytesPerLine: word;
  65.                          OtherStuff: array[69..128] of byte;
  66.                        end;
  67.  
  68.         VESAInfoRec = record
  69.                         Signature: array[0..3] of char;
  70.                         Version: word;
  71.                         OEMptr: pointer;
  72.                         Capabilities: array[0..3] of byte;
  73.                         ModePtr: pointer;
  74.         { There are reports of some VESA BIOSes returning more than 256
  75.           bytes from function 0, so this record is padded a bit. }
  76.                         Reserved: array[0..256] of byte;
  77.                       end;
  78.  
  79.         ModeInfoRec = record
  80.                         Attributes: word;
  81.                         WindowA_atts, windowB_atts: byte;
  82.                         GranuleKb, WindowKb: word;
  83.                         WindowAstart, WindowBstart: word;
  84.                         FunctionAddr: pointer;
  85.                         BytesPerLine: word;
  86.                         XRes, YRes: word;
  87.                         OtherStuff: array[23..256] of byte;
  88.                       end;
  89.  
  90. VAR
  91.         FileError: word;
  92.  
  93. FUNCTION DetectVESA(var VESAInf: VESAInfoRec): boolean;
  94. FUNCTION DetectVGA: boolean;
  95. FUNCTION HardwareSupports(Mode: word): boolean;
  96. FUNCTION WeSupport(Mode: word): boolean;
  97. FUNCTION GetMode: word;
  98. PROCEDURE SetMode(Mode, Options: word);
  99. PROCEDURE GetModeInfo(Mode: word; var ModeInfo: ModeInfoRec);
  100. FUNCTION OpenFile(PicFileName: pathstr; var PicFile: file;
  101.                   var Header: PCXHeaderRec): boolean;
  102. PROCEDURE ReportError(Error: word; var ErrorStr: string);
  103. FUNCTION ReadIt(PicFileName: pathstr; var Mode: word; Options: word): integer;
  104.  
  105. {========================================================================}
  106.  
  107. IMPLEMENTATION
  108.  
  109. CONST   MaxBufSize = 65024;
  110.  
  111. VAR
  112.         BufferSize: word;
  113.         PCXFilename: pathstr;
  114.         PCXHeader: PCXHeaderRec;
  115.         ModeInfo: ModeInfoRec;
  116.         RGBpal: array[0..15] of RGBrec;
  117.         RGB256: RGB256Rec;
  118.         VESAInfo: VESAInfoRec;
  119.         Regs: registers;
  120.         WindowEnd: word;
  121.         StartCol: word;
  122.         ColumnCount: word;
  123.         Plane: word;
  124.         BytesPerLine: word;
  125.         BytesPerScanLine: word;
  126.         XMax: word;
  127.         RepeatCount: byte;
  128.         DataLength: word;
  129.         WindowStep, WindowPos: word;
  130.         WriteWindow: byte;
  131.         VideoSeg, VideoOffs: word;
  132.         Scratch, LineBuf: pointer;
  133.         LineBufSeg, LineBufOffs: word;
  134.         LineBufIndex: word;
  135.         LineEnd, ScreenWidth: integer;
  136.         Margin: integer;
  137.  
  138. { ---------------------- Video mode routines ---------------------------- }
  139.  
  140. {$L VGAP}
  141.  
  142. PROCEDURE Decode16; far; external;
  143.  
  144. PROCEDURE Decode256; far; external;
  145.  
  146. PROCEDURE VideoOff(state: boolean);
  147.  
  148. { Hides the image by turning off video refresh. See Ferraro p. 468. }
  149.  
  150. begin
  151. regs.AH:= $12;
  152. regs.BL:= $36;
  153. regs.AL:= ord(state);
  154. intr($10, regs);
  155. end;
  156.  
  157. FUNCTION DetectVESA(var VESAInf: VESAInfoRec): boolean;
  158.  
  159. VAR  Signature: string[4];
  160.      IsVESA: boolean;
  161.  
  162. begin
  163. IsVESA:= False;
  164. Regs.AX:= $4F00;                { VESA Get SuperVGA Info function }
  165. Regs.ES:= seg(VESAInf);         { Info returns in VESAInfo record }
  166. Regs.DI:= ofs(VESAInf);
  167. intr($10, regs);
  168. if (Regs.AH = 0) then        { Function failed if AH <> 0 }
  169. begin
  170.   Signature[0]:= #4;
  171.   Move(VESAInf.Signature, Signature[1], 4);
  172.   if Signature = 'VESA' then IsVESA:= true;
  173. end;
  174. DetectVESA:= IsVESA;
  175. end;
  176.  
  177.  
  178. FUNCTION DetectVGA: boolean;
  179.  
  180. begin
  181. regs.AH:= $1A;               { See Ferraro p. 887 }
  182. regs.AL:= 0;
  183. intr($10, regs);
  184. DetectVGA:= (regs.AH <> $1A);
  185. end;
  186.  
  187.  
  188. FUNCTION HardwareSupports(Mode: word): boolean;
  189.  
  190. { VESA function $4F00 returns, among other things, a pointer to a list
  191.   of the video modes supported. The list terminates in $FFFF. }
  192.  
  193. type  ModeList = array[0..255] of word;
  194.  
  195. VAR  Supported: boolean;
  196.      Modes: ^ModeList;
  197.      x: integer;
  198.  
  199. begin
  200. Supported:= false;
  201. if Mode >= $100 then
  202. begin
  203.   if DetectVESA(VESAInfo) then    { Fills info record }
  204.   begin
  205.     x:= 0;
  206.     Modes:= VESAInfo.ModePtr;
  207.     repeat
  208.       if Modes^[x] = Mode then   { mode supported - but is window? }
  209.       begin
  210.         GetModeInfo(Mode, ModeInfo);
  211.         Supported:= (ModeInfo.WindowKb > 0);
  212.       end;
  213.       inc(x);
  214.     until Supported or (Modes^[x] = $FFFF) or (x = 256);
  215.   end else Halt;        { if VESA not detected - shouldn't get this far }
  216. end
  217. else Supported:= true;  { assume VGA present }
  218. HardwareSupports:= Supported;
  219. end;
  220.  
  221.  
  222. FUNCTION WeSupport(Mode: word): boolean;
  223.  
  224. { True if requested mode is supported by PCX.PAS }
  225.  
  226. VAR  x: integer;
  227.      InThere: boolean;
  228.  
  229. begin
  230. InThere:= false;
  231. for x:= 1 to NumModes do
  232.   if Mode = OurModes[x] then InThere:= true;
  233. WeSupport:= InThere;
  234. end;
  235.  
  236.  
  237. FUNCTION BestMode(Header: PCXHeaderRec): word;
  238.  
  239. { Attempts to match the mode to the originating format, but goes to a
  240.   higher resolution if the image doesn't fit the screen. }
  241.  
  242. VAR   M: word;
  243.  
  244.   PROCEDURE Try(Mode: word);
  245.  
  246.   begin
  247.   if HardwareSupports(Mode) and WeSupport(Mode) then M:= Mode;
  248.   end;
  249.  
  250.   FUNCTION Fits: boolean;
  251.  
  252.   begin
  253.   Fits:= (Header.XMax < Header.HRes) and (Header.YMax < Header.VRes);
  254.   end;
  255.  
  256. begin    { BestMode }
  257. if Header.NumPlanes = 1 then
  258. begin
  259.   M:= $13;
  260.   if (Header.HRes > 320) or (not Fits) then Try($101);
  261.   if (Header.HRes > 640) or (not Fits) then Try($103);
  262.   if (Header.HRes > 800) or (not Fits) then Try($105);
  263.   if (Header.HRes > 1024) or (not Fits) then Try($107);
  264. end
  265. else if Header.NumPlanes = 4 then
  266. begin
  267.   if Header.HRes <= 320 then M:= $0D else M:= $0E;
  268.   if (Header.VRes > 200) or (not Fits) then Try($10);
  269.   if (Header.VRes > 350) or (not Fits) then Try($12);
  270.   if (Header.VRes > 480) or (not Fits) then Try($102);
  271. end
  272. else M:= $FFFF;
  273. BestMode:= M;
  274. end;
  275.  
  276.  
  277. FUNCTION GetMode: word;
  278.  
  279. VAR  CurrMode: word;
  280.  
  281. begin
  282. if DetectVesa(VESAInfo) then
  283. begin
  284.   Regs.AX:= $4F03;
  285.   intr($10, Regs);
  286.   CurrMode:= Regs.BX;                  { may be inaccurate if not SVGA }
  287.   CurrMode:= CurrMode and $3FFF;       {  - see Wilton p. 448 }
  288.   if HardwareSupports(CurrMode) and (CurrMode >= $100) then
  289.   begin
  290.     GetMode:= CurrMode; exit;
  291.   end;
  292. end;
  293. Regs.AH:= $0F;                         { return VGA mode }
  294. intr($10, Regs);
  295. GetMode:= Regs.AL;
  296. end;
  297.  
  298.  
  299. PROCEDURE SetMode(Mode, Options: word);
  300.  
  301. begin
  302. if Mode >= $100 then
  303. { --- VESA Super-VGA modes }
  304. begin
  305.   if (Options and SaveMem) <> 0 then Mode:= Mode or $8000;
  306.                              { Set bit 15 to preserve video memory }
  307.   Regs.AX:= $4F02;
  308.   Regs.BX:= Mode;
  309. end else
  310. { --- Standard VGA modes }
  311. begin
  312.   if (Options and SaveMem) <> 0 then Mode:= Mode or $80;
  313.                              { Set bit 7 to preserve video memory }
  314.   Regs.AH:= 0;
  315.   Regs.AL:= lo(Mode);
  316. end;
  317. intr($10, Regs);
  318. end;  { SetMode }
  319.  
  320.  
  321. PROCEDURE GetModeInfo(Mode: word; var ModeInfo: ModeInfoRec);
  322.  
  323. { Puts information on the selected VESA mode into the ModeInfo record. }
  324.  
  325. begin
  326. Regs.AX:= $4f01;
  327. Regs.CX:= Mode;
  328. Regs.ES:= seg(ModeInfo);
  329. Regs.DI:= ofs(ModeInfo);
  330. intr($10, Regs);
  331. { Early versions of VESA BIOS extensions do not return values in the
  332.   XRes and YRes fields. We need to know the YRes for centering images. }
  333. with ModeInfo do
  334. case Mode of
  335.   $100: YRes:= 400;
  336.   $101: YRes:= 480;
  337.   $102: YRes:= 600;
  338.   $103: YRes:= 600;
  339.   $105: YRes:= 768;
  340.   $107: YRes:= 1024;
  341. end;
  342. end;
  343.  
  344. { ------------------------- Palette routines ---------------------------- }
  345.  
  346. FUNCTION Get256Palette(var TheFile: file; var PaletteStart: longint): boolean;
  347.  
  348. { TheFile must be open. }
  349.  
  350. VAR    x: integer;
  351.        PaletteFlag: byte;
  352.  
  353. begin
  354. PaletteStart:= filesize(TheFile) - 769;
  355.  
  356. { The last 769 btes of the file are palette information, starting with a
  357.    one-byte flag. Each group of three bytes represents the RGB values of
  358.    one of the color registers. We take the 6 most significant bits
  359.    to bring the values within the range 0-63 expected by the registers. }
  360.  
  361. seek(TheFile, PaletteStart);
  362. blockread(TheFile, PaletteFlag, 1);
  363. if (PaletteFlag <> 12) or (PCXHeader.Version < 5) then
  364. begin
  365.   FileError:= ErrNoPal;
  366.   Get256Palette:= false;
  367.   exit;
  368. end;
  369. blockread(TheFile, RGB256, 768);         { Get palette info. }
  370. for x:= 0 to 255 do
  371. with RGB256[x] do
  372. begin
  373.   RedVal:= RedVal shr 2;
  374.   GreenVal:= GreenVal shr 2;
  375.   BlueVal:= BlueVal shr 2;
  376. end;
  377. Get256Palette:= true;
  378. end;  { Get256Palette }
  379.    
  380.  
  381. PROCEDURE SetColorRegisters(var PalRec);
  382.  
  383. { We can't use the BGI's SetRGBPalette even for the modes supported by
  384.   the BGI, because it won't work unless the BGI initializes the mode
  385.   itself. }
  386.  
  387. { PalRec is a string of 768 bytes containing the RGB data. }
  388.  
  389. begin
  390. Regs.AH:= $10;               { BIOS color register function }
  391. Regs.AL:= $12;               { Subfunction }
  392. Regs.ES:= seg(PalRec);       { Address of palette info }
  393. Regs.DX:= ofs(PalRec);
  394. Regs.BX:= 0;                 { First register to change }
  395. Regs.CX:= $100;              { Number of registers to change }
  396. intr($10, Regs);             { Call BIOS }
  397. end;
  398.  
  399.  
  400. PROCEDURE SetPalette(var Palette);
  401.  
  402. { Replaces the BGI SetAllPalette procedure. Palette is a 17-byte record
  403.   of the contents of the 16 EGA/VGA palette registers plus the overscan
  404.   register. }
  405.  
  406. begin
  407. Regs.AH:= $10;
  408. Regs.AL:= 2;
  409. Regs.ES:= seg(Palette);
  410. Regs.DX:= ofs(Palette);
  411. intr($10, Regs);
  412. end;
  413.  
  414. { ------------------------ Miscellaneous routines ------------------------ }
  415.  
  416. PROCEDURE GetMargin(ScreenWidth: word; var Margin, LineEnd: integer);
  417.  
  418. { Calculate how many pixels have to be skipped when advancing to the
  419.   next line, so that files of less than screen width can be displayed. }
  420.  
  421. begin
  422. LineEnd:= PCXHeader.BytesPerLine;      { Used as counter in assembler }
  423. Margin:= ScreenWidth - LineEnd;
  424. if Margin < 0 then FileError:= ErrTooWide;
  425. end;
  426.  
  427.  
  428. FUNCTION SetBufferSize: word;
  429.  
  430. begin
  431. if MaxBufSize > MaxAvail then SetBufferSize:= MaxAvail
  432. else SetBufferSize:= MaxBufSize;
  433. end;
  434.  
  435.  
  436. PROCEDURE ReportError(Error: word; var ErrorStr: string);
  437.  
  438. begin
  439. case Error of
  440.   ErrNoOpen:  ErrorStr:= 'Could not open file.';
  441.   ErrNoPal:   ErrorStr:= 'No palette information in file.';
  442.   ErrTooWide: ErrorStr:= 'Picture is too wide for requested video mode.';
  443.   ErrColors:  ErrorStr:= 'Number of colors in file does not match selected mode.';
  444.   ErrNoSupp:  ErrorStr:= 'Unsupported picture format.';
  445. end;
  446. end;
  447.  
  448.    
  449. FUNCTION OpenFile(PicFileName: pathstr; var PicFile: file;
  450.                   var Header: PCXHeaderRec): boolean;
  451.  
  452. begin
  453. assign(PicFile, PicFileName);
  454. {$I-} reset(PicFile, 1);
  455. blockread(PicFile, Header, 128);  {$I+}
  456. OpenFile:= IOresult = 0;
  457. end;
  458.  
  459. FUNCTION GetFirstPix(var Header: PCXHeaderRec;
  460.                      Options, ScreenWid, ScreenHt: word): longint;
  461.  
  462. { The image is centered if the Options call for it. Otherwise it is offset
  463.   on the screen according to the values of XMin and YMin in the file header.
  464.   These are usually zero. This function returns the offset in bytes from
  465.   the start of the video buffer to where the first pixel will be written. }
  466.  
  467. VAR  FirstPix: longint;
  468.      PicWid, PicHt: integer;
  469.  
  470. begin
  471. FirstPix:= 0;
  472. with Header do
  473. begin
  474.   PicWid:= (XMax - XMin + 1);
  475.   if BitsPerPlane = 1 then PicWid:= PicWid div 8;
  476.   PicHt:= YMax - YMin + 1;
  477.   if PicHt < ScreenHt then (* INC(FIRSTPIX, 10240); *)
  478.   begin
  479.     if (Options and VCenter) = 0 then
  480.       inc(FirstPix, YMin * ScreenWid)
  481.     else inc(FirstPix, longint((ScreenHt-1-PicHt) div 2) * ScreenWid);
  482.   end;
  483.   if PicWid < ScreenWid then
  484.   begin
  485.     if (Options and HCenter) = 0 then inc(FirstPix, XMin)
  486.     else inc(FirstPix, (ScreenWid - PicWid) div 2);
  487.   end;
  488. end;   { with }
  489. GetFirstPix:= FirstPix;
  490. end;
  491.  
  492. { -------------------------- VGA 16-color files ------------------------- }
  493.  
  494. PROCEDURE Read16(var PicFile: file; Mode, Options: word);
  495.  
  496. TYPE
  497.         PaletteBytes = array[0..2] of byte;
  498.  
  499. VAR
  500.         Entry, Gun, PCXCode: byte;
  501.         PalRegs: array[0..16] of byte;
  502.         ScreenHeight: word;
  503.  
  504. begin   { READ16 }
  505. if PCXHeader.NumPlanes <> 4 then
  506. begin
  507.   FileError:= ErrColors;
  508.   exit;
  509. end;
  510. if Mode >= $100 then
  511. begin
  512.   GetModeInfo(Mode, ModeInfo);
  513.   ScreenWidth:= ModeInfo.BytesPerLine;
  514.   ScreenHeight:= ModeInfo.YRes;
  515. end
  516. else case Mode of
  517.   $0D: begin ScreenWidth:= 40; ScreenHeight:= 200; end;
  518.   $0E: begin ScreenWidth:= 80; ScreenHeight:= 200; end;
  519.   $10: begin ScreenWidth:= 80; ScreenHeight:= 350; end;
  520.   $12: begin ScreenWidth:= 80; ScreenHeight:= 480; end;
  521. end;
  522. GetMargin(ScreenWidth, Margin, LineEnd);
  523. if FileError <> 0 then exit;
  524. VideoOffs:= GetFirstPix(PCXHeader, Options, ScreenWidth, ScreenHeight);
  525. VideoSeg:= $A000;         { Segment of video memory }
  526. port[$3C4]:= 2;           { Index to map mask register }
  527. Plane:= 1;                { Initialize plane }
  528. port[$3C5]:= Plane;       { Set sequencer to mask out other planes }
  529.  
  530. { --- Decipher 16-color palette --- }
  531.  
  532. {  The palette information is stored in bytes 16-63 of the header. Each of
  533.    the 16 palette slots is allotted 3 bytes - one for each primary color.
  534.    Any of these bytes can have a value of 0-255. However, the VGA is
  535.    capable only of 6-bit RGB values (making for 64x64x64 = 256K possible
  536.    colors), so we take only the 6 most significant bits from each PCX
  537.    color value.
  538.  
  539.    In 16-color modes, the VGA uses the 16 CGA/EGA palette registers.
  540.    However, the actual color values (18 bits per slot) won't fit here,
  541.    so the palette registers are used as pointers to 16 of the 256 color
  542.    registers, which hold the RGB values.
  543.  
  544.    What we have to do is extract the RGB values from the PCX header, put
  545.    them in the first 16 color registers, then set the palette to point to
  546.    those registers. }
  547.  
  548. for Entry:= 0 to 15 do
  549. begin
  550.   for Gun:= 0 to 2 do
  551.   begin
  552.     PCXCode:= PaletteBytes(PCXHeader.Palette[entry])[Gun];
  553.     with RGBPal[Entry] do
  554.     case gun of
  555.       0: RedVal:= PCXCode shr 2;
  556.       1: GreenVal:= PCXCode shr 2;
  557.       2: BlueVal:= PCXCode shr 2;
  558.     end;
  559.   end;  { gun }
  560.   PalRegs[Entry]:= Entry;
  561. end;  { Entry }
  562. PalRegs[16]:= 0;                       { overscan color }
  563. SetColorRegisters(RGBPal);             { RGB values into registers 0-15 }
  564. SetPalette(PalRegs);                   { point to registers 0-15 }
  565.  
  566. { --- Read and decode the image data --- }
  567.  
  568. BytesPerLine:= PCXHeader.BytesPerLine;
  569. RepeatCount:= 0;                       { Initialize assembler vars. }
  570. ColumnCount:= 0;
  571. seek(PicFile, 128);
  572. BufferSize:= SetBufferSize;
  573. getmem(Scratch, BufferSize);           { Allocate scratchpad }
  574. repeat
  575.   blockread(PicFile, Scratch^, BufferSize, DataLength);
  576.   Decode16;                           { Call assembler routine }
  577. until eof(PicFile);
  578. port[$3C5]:= $F;                       { Reset mask map }
  579. freemem(Scratch,BufferSize);           { Discard scratchpad }
  580. end;  { READ16 }
  581.  
  582. { ------------------------- VGA 256-color files ------------------------- }
  583.  
  584. PROCEDURE ReadVGA256(var PicFile: file; Mode, Options: word);
  585.  
  586. VAR     TotalRead: longint;
  587.         PaletteStart: longint;
  588.  
  589. begin
  590. if PCXHeader.NumPlanes <> 1 then
  591. begin
  592.   FileError:= ErrColors;
  593.   exit;
  594. end;
  595. { --- Set palette  --- }
  596. if not Get256Palette(PicFile, PaletteStart) then exit;
  597. { If clearing video memory before displaying the picture (the default),
  598.   we wait till the entire picture is in memory before displaying it,
  599.   to give a better effect. This is done by setting all color registers
  600.   to black. Otherwise the picture colors are set before any of it is
  601.   displayed. }
  602. SetColorRegisters(RGB256);
  603. ScreenWidth:= 320;
  604. GetMargin(ScreenWidth, Margin, LineEnd);
  605. if FileError <> 0 then exit;
  606.  
  607. { --- Read image data --- }
  608. seek(PicFile, 128);
  609. TotalRead:= 128;
  610. repeatcount:= 0;                           { Initialize assembler vars. }
  611. VideoOffs:= GetFirstPix(PCXHeader, Options, ScreenWidth, 200);
  612. VideoSeg:= $A000;
  613. BufferSize:= SetBufferSize;
  614. getmem(Scratch, BufferSize);                { Allocate scratchpad }
  615. repeat
  616.   blockread(PicFile, Scratch^, BufferSize, DataLength);
  617.   inc(TotalRead, DataLength);
  618.   if (TotalRead > PaletteStart) then
  619.       dec(DataLength, TotalRead - PaletteStart);
  620.   Decode256;
  621. until (eof(PicFile)) or (TotalRead>= PaletteStart);
  622. freemem(Scratch, BufferSize);
  623. end;  { ReadVGA256 }
  624.  
  625. { ------------------------- SVGA 256-color files ------------------------ }
  626.  
  627. {$IFDEF RegisteredVersion}
  628.   {$I SVGA256.PAS}
  629. {$ELSE}
  630.  
  631. PROCEDURE ReadSVGA256(var PicFile: file; Mode, Options: word);
  632.  
  633. begin
  634.   SetMode(3, NoOptions);
  635.   Writeln('Support for this video mode is available only to registered');
  636.   Writeln('users of PCX.PAS. Please see READ.ME for details.');
  637.   Writeln;
  638. end;
  639.  
  640. {$ENDIF}
  641.  
  642. { -------------------------- Main Procedure ----------------------------- }
  643.  
  644. FUNCTION ReadIt(PicFileName: pathstr; var Mode: word; Options: word): integer;
  645.  
  646. VAR  PCXfile: file;
  647.  
  648. begin
  649. FileError:= 0;
  650. if not OpenFile(PicFileName, PCXFile, PCXHeader) then           { Gets PCX header }
  651. begin
  652.   ReadIt:= 1;
  653.   exit;
  654. end;
  655. { Trap CGA files }
  656. if (PCXHeader.BitsPerPlane < 8) and (PCXHeader.NumPlanes = 1) then
  657. begin
  658.   close(PCXFile);
  659.   ReadIt:= 5;
  660.   exit;
  661. end;
  662. if Mode = AutoSet then Mode:= BestMode(PCXHeader);
  663. if Mode = $FFFF then             { couldn't find a workable mode }
  664. begin
  665.   FileError:= ErrNoSupp;
  666.   exit;
  667. end;
  668. SetMode(Mode, Options);
  669. if (Options and Blackout) > 0 then VideoOff(true);
  670. case Mode of
  671.   $0D, $0E, $10, $12, $102: Read16(PCXFile, Mode, Options);
  672.   $13: ReadVGA256(PCXFile, Mode, Options);
  673.   $100, $101, $103, $105, $107: ReadSVGA256(PCXFile, Mode, Options);
  674. end;
  675. if (Options and Blackout) > 0 then VideoOff(false);
  676. close(PCXFile);
  677. ReadIt:= FileError;
  678. end;
  679.  
  680. BEGIN
  681. END.
  682.